package com.only4play.importapt.service;


import jakarta.annotation.PostConstruct;
import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.*;

@Slf4j
public abstract class AbstractMergeRequestService {
    // 配置中心合并请求开关
    private boolean enableMerge = true;

    // 封装的请求
    @NoArgsConstructor
    @AllArgsConstructor
    @Getter
    @Setter
    public static class WrapRequest {
        private String requestId;

        // 参数Id
        private String userId;
        CompletableFuture<Object> future;

    }

    // 创建用来存放请求的区域，将请求封装成一个Request对象
    // 可以用redis或其他组件
    private LinkedBlockingQueue<WrapRequest> requestMergeRegion = new LinkedBlockingQueue<>();

    // query方法，通过判断是否需要合并请求
    public Object query(WrapRequest request) throws ExecutionException, InterruptedException {
        if (enableMerge) {
            // 创建request，并为request创建CompletableFuture对象
            // 将request添加到 存放请求的位置
            requestMergeRegion.add(request);
            // 阻塞，直到结果返回
            return request.getFuture().get();
        } else {
            // 单独处理逻辑
            return noneMergeAndSingleExecute(request);
        }
    }

    // 使用定时任务批量执行合并请求
    @PostConstruct
    public void init() {
        // 在init方法中初始化一个定时任务，去定时执行我们的批量任务
        // 合并请求
        // 拆分结果
        ScheduledExecutorService poolExecutor = new ScheduledThreadPoolExecutor(1);
        poolExecutor.scheduleAtFixedRate(() -> {
            int size = requestMergeRegion.size();
            // 如果没有请求直接返回
            if (size == 0) {
                return;
            }

            log.info("当前合并请求个数为：{}", size);

            // 获取当前queue中的所有请求
            List<WrapRequest> list = new ArrayList<>();
            for (int i = 0; i < size; i++) {
                WrapRequest request = requestMergeRegion.poll();
                list.add(request);
            }

            // 模版方法1: 合并请求并批量执行
            Object response = mergeRequestAndExecute(list);

            // 模版方法2: 分发结果给不同的请求的future
            splitResponse(list, response);
        }, 0, 200, TimeUnit.MILLISECONDS);
    }

    protected abstract Object noneMergeAndSingleExecute(WrapRequest request);

    // 由不同的处理逻辑来实现
    protected abstract Object mergeRequestAndExecute(List<WrapRequest> list);

    // 由不同的处理逻辑来实现
    protected abstract void splitResponse(List<WrapRequest> list, Object response);
}
